package core;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Floor implements Serializable {
	private static final long serialVersionUID = -2524877175083650036L;

	public Room[] rooms;
	public Door[] doors;

	public boolean there_s_smoking, there_s_flowers;

	public Floor() {
		this.doors = new Door[4];

		this.rooms = new Room[4];

		this.generateObject();

		there_s_smoking = true;
		there_s_flowers = true;
	}

	public void generateObject() {
		List<Integer> tmp = new ArrayList<Integer>();
		Random random = new Random();
		int next = -1;
		for (int i = 0; i < 4; i++) {
			do {
				next = Math.abs(random.nextInt()) % 4;
			} while (tmp.contains(next));
			tmp.add(next);
			switch (next) {
			case 0:
				this.rooms[i] = new Room(Room.Type.bedroom);
				break;
			case 1:
				this.rooms[i] = new Room(Room.Type.hall);
				break;
			case 2:
				this.rooms[i] = new Room(Room.Type.kitchen);
				break;
			case 3:
				this.rooms[i] = new Room(Room.Type.living);
				break;
			default:
				break;
			}
			next = Math.abs(random.nextInt()) % 8;
			this.doors[i] = new Door(i, next);
		}
	}

	public void load(Floor floor) {
		this.rooms = floor.rooms;
	}

	public Square.Type get(int i, int j) {
		if (i < 0 || j < 0 || i >= 4 || j >= 8)
			return Square.Type.Unknown;
		return this.rooms[i].squares[j].type;
	}

	public int get(String roomType) {
		for (int i = 0; i < this.rooms.length; i++)
			if (this.rooms[i].equals(roomType))
				return i;
		return -1;
	}

	public void set(int i, int j, Square.Type st) {
		if (i < 0 || j < 0 || i >= 4 || j >= 8)
			return;
		this.rooms[i].squares[j].type = st;
	}

	public boolean isDoor(int row, int column) {
		if (this.doors[row].row == row && this.doors[row].col == column)
			return true;
		if (row == 0)
			return false;
		if (this.doors[row - 1].row == row && this.doors[row - 1].col == column)
			return true;
		return false;
	}

	public boolean dynamic1() {
		Random random = new Random();
		Square.Type to_change = null;
		if (random.nextInt() % 2 == 0) {
			if (there_s_flowers)
				to_change = Square.Type.Flowers;
			else if (there_s_smoking)
				to_change = Square.Type.Smoking;

		} else if (there_s_smoking)
			to_change = Square.Type.Smoking;
		else if (there_s_flowers)
			to_change = Square.Type.Flowers;
		else
			return false;

		int new_position;
		for (int i = 0; i < this.rooms.length; i++) {
			for (int j = 0; j < 8; j++) {
				if (this.rooms[i].squares[j].type == to_change) {
					this.rooms[i].squares[j].type = Square.Type.Clean;
					do {
						new_position = Math.abs(random.nextInt()) % 8;
					} while (new_position == j
							|| this.rooms[i].squares[new_position].type != Square.Type.Clean);
					this.rooms[i].squares[new_position].type = to_change;
					return true;
				}
			}
		}
		return false;
	}

	public boolean dynamic2() {
		Random random = new Random();
		Square.Type to_change = null;
		boolean change_both;

		if (random.nextInt() % 2 == 0) {
			System.out.println("Sposto un solo oggetto");
			change_both = false;
			if (random.nextInt() % 2 == 0)
				if (there_s_flowers)
					to_change = Square.Type.Flowers;
				else if (there_s_smoking)
					to_change = Square.Type.Smoking;
				else
					return false;
			else if (there_s_smoking)
				to_change = Square.Type.Smoking;
			else if (there_s_flowers)
				to_change = Square.Type.Flowers;

		} else {
			change_both = true;
			System.out.println("Sposto entrambi gli oggetti");
			to_change = null;
		}

		int new_position;

		for (int i = 0; i < this.rooms.length; i++) {
			for (int j = 0; j < 8; j++) {
				if (change_both) {
					if (this.rooms[i].squares[j].type == Square.Type.Flowers
							|| this.rooms[i].squares[j].type == Square.Type.Smoking)
						to_change = this.rooms[i].squares[j].type;
					else
						to_change = null;
				}

				if (this.rooms[i].squares[j].type == to_change) {
					this.rooms[i].squares[j].type = Square.Type.Clean;
					do {
						new_position = Math.abs(random.nextInt()) % 8;
					} while (new_position == j
							|| this.rooms[i].squares[new_position].type != Square.Type.Clean);
					this.rooms[i].squares[new_position].type = to_change;
					return true;
				}
			}
		}
		return false;
	}

	public boolean dynamic3() {
		Random random = new Random();
		Square.Type to_change = null;
		boolean change_both;

		if (random.nextInt() % 2 == 0) {
			System.out.println("Sposto un solo oggetto");
			change_both = false;
			if (random.nextInt() % 2 == 0)
				if (there_s_flowers)
					to_change = Square.Type.Flowers;
				else if (there_s_smoking)
					to_change = Square.Type.Smoking;
				else
					return false;
			else if (there_s_smoking)
				to_change = Square.Type.Smoking;
			else if (there_s_flowers)
				to_change = Square.Type.Flowers;

		} else {
			change_both = true;
			System.out.println("Sposto entrambi gli oggetti");
			to_change = null;
		}

		int new_position_i, new_position_j;

		for (int i = 0; i < this.rooms.length; i++) {
			for (int j = 0; j < 8; j++) {
				if (change_both) {
					if (this.rooms[i].squares[j].type == Square.Type.Flowers
							|| this.rooms[i].squares[j].type == Square.Type.Smoking)
						to_change = this.rooms[i].squares[j].type;
					else
						to_change = null;
				}

				if (this.rooms[i].squares[j].type == to_change) {
					this.rooms[i].squares[j].type = Square.Type.Clean;
					do {
						new_position_i = Math.abs(random.nextInt()) % 4;
						new_position_j = Math.abs(random.nextInt()) % 8;
					} while ((new_position_i == i && new_position_j == j)
							|| this.rooms[new_position_i].squares[new_position_j].type != Square.Type.Clean);
					this.rooms[new_position_i].squares[new_position_j].type = to_change;
					return true;
				}
			}
		}
		return false;
	}

	private Square.Type getNewObject() {
		Random random = new Random();
		int tmp = Math.abs(random.nextInt() % 4);
		switch (tmp) {
		case 0:
			return Square.Type.Flowers;
		case 1:
			return Square.Type.Meal;
		case 2:
			return Square.Type.Smoking;
		case 3:
			return Square.Type.Table;
		default:
			break;
		}
		return Square.Type.Clean;
	}

	public void dynamic2_old() {
		Random random = new Random();
		int tmp = -1;
		for (int i = 0; i < this.rooms.length; i++) {
			for (int j = 0; j < 8; j++) {
				if (this.rooms[i].squares[j].type != Square.Type.Clean) {
					Square.Type s = this.rooms[i].squares[j].type;
					this.rooms[i].squares[j].type = Square.Type.Clean;
					do {
						tmp = Math.abs(random.nextInt() % 8);
					} while (tmp == j);
					this.rooms[i].squares[tmp].type = s;
				}
			}
		}
	}

	public void dynamic3_old() {
		Random random = new Random();
		int tmp = -1;
		Square.Type newObject = null;
		// Per ogni stanza
		for (int i = 0; i < this.rooms.length; i++) {
			// Cerco l'oggetto
			for (int j = 0; j < 8; j++) {
				if (this.rooms[i].squares[j].type != Square.Type.Clean) {
					this.rooms[i].squares[j].type = Square.Type.Clean;
					// Scelgo il nuovo oggetto
					do {
						newObject = getNewObject();
					} while (!containsRoom(i, newObject));
					// Scelgo la nuova posizione dell'oggetto
					do {
						tmp = Math.abs(random.nextInt()) % 8;
					} while (tmp == j);
					this.rooms[i].squares[tmp].type = newObject;
					break;
				}
			}
		}
	}

	private boolean containsRoom(int n, Square.Type newObject) {
		// Le stanze precedenti non devono contenere l'oggetto newObject.
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < 8; j++) {
				if (this.rooms[i].squares[j].type == newObject)
					return false;
			}
		}
		return true;
	}
}